package com.example;

import com.example.config.AppConfig;
import com.example.service.CalculatorService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

/**
 * 主应用程序类
 * 演示Spring IoC和AOP的使用
 */
public class Application {
    
    private static final Logger logger = LoggerFactory.getLogger(Application.class);
    
    public static void main(String[] args) {
        logger.info("=== Spring IoC和AOP演示程序启动 ===");
        
        // 创建Spring容器（IoC容器）
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
        
        // 从容器中获取CalculatorService实例（依赖注入）
        CalculatorService calculator = context.getBean(CalculatorService.class);
        
        logger.info("=== 开始演示计算器功能 ===");
        
        // 演示加法运算（带缓存）
        demonstrateAdd(calculator);
        
        // 演示减法运算（带缓存）
        demonstrateSubtract(calculator);
        
        // 演示乘法运算（无缓存，只有日志）
        demonstrateMultiply(calculator);
        
        // 演示除法运算（异常处理）
        demonstrateDivide(calculator);
        
        // 演示幂运算（带缓存）
        demonstratePower(calculator);
        
        // 演示阶乘运算（带缓存）
        demonstrateFactorial(calculator);
        
        // 演示缓存效果
        demonstrateCacheEffect(calculator);
        
        logger.info("=== 演示程序结束 ===");
        
        // 关闭Spring容器
        context.close();
    }
    
    private static void demonstrateAdd(CalculatorService calculator) {
        logger.info("\n--- 演示加法运算 ---");
        double result1 = calculator.add(10, 5);
        logger.info("10 + 5 = {}", result1);
        
        // 再次调用相同参数，应该从缓存获取
        double result2 = calculator.add(10, 5);
        logger.info("10 + 5 = {} (应该从缓存获取)", result2);
    }
    
    private static void demonstrateSubtract(CalculatorService calculator) {
        logger.info("\n--- 演示减法运算 ---");
        double result1 = calculator.subtract(10, 3);
        logger.info("10 - 3 = {}", result1);
        
        // 再次调用相同参数，应该从缓存获取
        double result2 = calculator.subtract(10, 3);
        logger.info("10 - 3 = {} (应该从缓存获取)", result2);
    }
    
    private static void demonstrateMultiply(CalculatorService calculator) {
        logger.info("\n--- 演示乘法运算（无缓存） ---");
        double result1 = calculator.multiply(6, 7);
        logger.info("6 * 7 = {}", result1);
        
        // 再次调用，没有缓存，会重新计算
        double result2 = calculator.multiply(6, 7);
        logger.info("6 * 7 = {} (重新计算)", result2);
    }
    
    private static void demonstrateDivide(CalculatorService calculator) {
        logger.info("\n--- 演示除法运算（异常处理） ---");
        try {
            double result = calculator.divide(10, 2);
            logger.info("10 / 2 = {}", result);
        } catch (Exception e) {
            logger.error("除法运算异常: {}", e.getMessage());
        }
        
        try {
            double result = calculator.divide(10, 0);
            logger.info("10 / 0 = {}", result);
        } catch (Exception e) {
            logger.error("除法运算异常: {}", e.getMessage());
        }
    }
    
    private static void demonstratePower(CalculatorService calculator) {
        logger.info("\n--- 演示幂运算 ---");
        double result1 = calculator.power(2, 8);
        logger.info("2 ^ 8 = {}", result1);
        
        // 再次调用相同参数，应该从缓存获取
        double result2 = calculator.power(2, 8);
        logger.info("2 ^ 8 = {} (应该从缓存获取)", result2);
    }
    
    private static void demonstrateFactorial(CalculatorService calculator) {
        logger.info("\n--- 演示阶乘运算 ---");
        long result1 = calculator.factorial(5);
        logger.info("5! = {}", result1);
        
        // 再次调用相同参数，应该从缓存获取
        long result2 = calculator.factorial(5);
        logger.info("5! = {} (应该从缓存获取)", result2);
        
        try {
            long result3 = calculator.factorial(-1);
            logger.info("-1! = {}", result3);
        } catch (Exception e) {
            logger.error("阶乘运算异常: {}", e.getMessage());
        }
    }
    
    private static void demonstrateCacheEffect(CalculatorService calculator) {
        logger.info("\n--- 演示缓存效果 ---");
        
        // 第一次调用，会计算
        logger.info("第一次调用阶乘 6!");
        long start1 = System.currentTimeMillis();
        long result1 = calculator.factorial(6);
        long end1 = System.currentTimeMillis();
        logger.info("6! = {}, 耗时: {}ms", result1, end1 - start1);
        
        // 第二次调用，从缓存获取
        logger.info("第二次调用阶乘 6!");
        long start2 = System.currentTimeMillis();
        long result2 = calculator.factorial(6);
        long end2 = System.currentTimeMillis();
        logger.info("6! = {}, 耗时: {}ms (从缓存获取)", result2, end2 - start2);
        
        // 调用不同参数，重新计算
        logger.info("调用阶乘 7!");
        long start3 = System.currentTimeMillis();
        long result3 = calculator.factorial(7);
        long end3 = System.currentTimeMillis();
        logger.info("7! = {}, 耗时: {}ms", result3, end3 - start3);
    }
}
